﻿/*
 *   Copyright 2011 Peter Crossley
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 *  ----------------------------------------------------------------------------
 *  File:       ConfigBuilder.cs
 *  Author:     Peter Crossley
 *  ----------------------------------------------------------------------------
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using UEC;
namespace UEC.Modules.Configuration
{
    public partial class ConfigBuilder : UserControl
    {
        private ConfigurationService service;
        private CloudManager manager;
        public ConfigBuilder(ConfigurationService service)
        {
            this.service = service;
            this.manager = service.Manager;
            
            InitializeComponent();
            LoadCloudInit(manager.CloudInit);
        }


        private void ConfigBuilder_Load(object sender, EventArgs e)
        {
            //settings validations
            this.dataGridSettings.CellValidating += new DataGridViewCellValidatingEventHandler(this.dataGridSettings_CellValidating);
            this.dataGridSettings.CellEndEdit += new DataGridViewCellEventHandler(this.dataGridSettings_CellEndEdit);
            this.dataGridSettings.CellValueChanged += new DataGridViewCellEventHandler(this.dataGridSettings_CellValueChanged);
            this.dataGridSettings.RowValidating += new DataGridViewCellCancelEventHandler(this.dataGridSettings_RowValidating);

            //script validations
            this.dataGridScripts.CellValidating += new DataGridViewCellValidatingEventHandler(this.dataGridScripts_CellValidating);
            this.dataGridScripts.CellEndEdit += new DataGridViewCellEventHandler(this.dataGridScripts_CellEndEdit);
            this.dataGridScripts.CellValueChanged += new DataGridViewCellEventHandler(this.dataGridScripts_CellValueChanged);
            this.dataGridScripts.RowValidating += new DataGridViewCellCancelEventHandler(this.dataGridScripts_RowValidating);
        }

        private void btnReset_Click(object sender, EventArgs e)
        {
            dataGridSettings.Rows.Clear();
            dataGridScripts.Rows.Clear();
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            ofd.Title = "Load Cloud Configuration Data";
            ofd.Filter = "XML Files (*.xml)|*.xml";
            if (DialogResult.OK == ofd.ShowDialog())
            {
                CloudInit cloud = ConfigurationService.DeserializeCloudInitFromXML(File.ReadAllText(ofd.FileName));
                LoadCloudInit(cloud);
            }
        }

        private void LoadCloudInit(CloudInit cloud)
        {
            if (cloud == null)
            {
                return;
            }

            if (cloud.Settings != null)
            {
                foreach (Config c in cloud.Settings)
                {
                    string[] row = { c.Section, c.Name, c.Value };
                    dataGridSettings.Rows.Add(row);
                }
            }

            if (cloud.Scripts != null)
            {
                foreach (ProcessScript c in cloud.Scripts)
                {
                    string[] row = { c.Name, c.Source, "...", c.Script, c.Interpreter, c.Interactive.ToString(), c.Elevate.ToString(), c.AllowReboot.ToString(),c.Weight.ToString(), c.Arguments, c.Extention, c.Type.ToString() };
                    dataGridScripts.Rows.Add(row);
                }

            }

        }

        private CloudInit SaveCloudInit()
        {
            CloudInit cloud = new CloudInit();
            List<Config> settings = new List<Config>(dataGridSettings.Rows.Count-1);
            for (int i = 0; i < dataGridSettings.Rows.Count-1; i++)
            {
                Config c = new Config();
                DataGridViewRow row = dataGridSettings.Rows[i];
                c.Section = (string)row.Cells["colSection"].Value;
                c.Name = (string)row.Cells["colName"].Value;
                c.Value = (string)row.Cells["colValue"].Value;
                settings.Add(c);
            }
            cloud.Settings = settings;

            List<ProcessScript> scripts = new List<ProcessScript>(dataGridScripts.Rows.Count-1);
            for (int i = 0; i < dataGridScripts.Rows.Count-1; i++)
            {
                ProcessScript c = new ProcessScript();
                DataGridViewRow row = dataGridScripts.Rows[i];
                c.Name = (string)row.Cells["colScriptName"].Value;
                c.Script = (string)row.Cells["colScriptData"].Value;
                c.Source = (string)row.Cells["colSource"].Value;
                c.Interpreter = (string)row.Cells["colInterpreter"].Value;
                c.Interactive = (bool)row.Cells["colInteractive"].Value;
                c.AllowReboot = (bool)row.Cells["colAllowReboot"].Value;
                int weight = 0;
                int.TryParse((string)row.Cells["colWeight"].Value, out weight);
                c.Weight = weight;
                c.Arguments = (string)row.Cells["colArguments"].Value;
                if (c.Source != null && String.IsNullOrEmpty((string)row.Cells["colExtention"].Value))
                {
                    string ext = Path.GetExtension(c.Source);
                    if (!String.IsNullOrEmpty(ext))
                    {
                        c.Extention = ext.Substring(1);
                    }
                }
                else
                {
                    c.Extention = (string)row.Cells["colExtention"].Value;
                }
                c.Elevate = (bool)row.Cells["colElevate"].Value;

                ProcessScript.ScriptType type = (ProcessScript.ScriptType) Enum.Parse(typeof(ProcessScript.ScriptType), (string)row.Cells["colType"].Value);
                c.Type = type;
                if (string.IsNullOrEmpty(c.Name) || (string.IsNullOrEmpty(c.Script) && string.IsNullOrEmpty(c.Source)))
                {
                    continue;
                }
                scripts.Add(c);
            }
            cloud.Scripts = scripts;

            return cloud;
        }

        private void Generate_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "Save Cloud Configuration Data";
            sfd.Filter = "XML Files (*.xml)|*.xml";
            sfd.AddExtension = true;
            sfd.DefaultExt = "xml";

            DialogResult rs = sfd.ShowDialog();
            if (DialogResult.OK == rs)
            {
                string data = ConfigurationService.SerializeCloudInitToXML(SaveCloudInit());
                File.WriteAllText(sfd.FileName, data);                
            }
        }

        /*
         * Script Box support
         */
        
        private DataGridViewCell _scriptCell;
        private void dataGridScripts_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            int scriptIndx = dataGridScripts.Rows[e.RowIndex].Cells["colScript"].ColumnIndex;
            if (e.ColumnIndex != scriptIndx)
            {
                //wrong column
                return;
            }
            _scriptCell = dataGridScripts.Rows[e.RowIndex].Cells["colScriptData"];
            ScriptBox box = new ScriptBox();
            box.FormClosing += new FormClosingEventHandler(this.ScriptBox_FormClosing);
            box.Script = (string)_scriptCell.Value;
            box.ShowDialog();
        }

        private void ScriptBox_FormClosing(object sender, FormClosingEventArgs e)
        {
            _scriptCell.Value = ((ScriptBox)sender).Script;
            dataGridScripts.Rows[_scriptCell.RowIndex].Cells["colSource"].Value = null;
            _scriptCell = null;
        }


        // Settings Validation

        private void dataGridSettings_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (!_cellDirty)
            {
                return;
            }
            // Validate the Section, Name entry by disallowing empty strings.
            if (dataGridSettings.Columns[e.ColumnIndex].Name == "colSection")
            {
                if (String.IsNullOrEmpty(e.FormattedValue.ToString()))
                {
                    dataGridSettings.Rows[e.RowIndex].ErrorText =
                        "Section must not be empty";
                    e.Cancel = true;
                }
            }
            else if (dataGridSettings.Columns[e.ColumnIndex].Name == "colName")
            {
                if (String.IsNullOrEmpty(e.FormattedValue.ToString()))
                {
                    dataGridSettings.Rows[e.RowIndex].ErrorText =
                        "Name must not be empty";
                    e.Cancel = true;
                }
            }
        }

        private bool _cellDirty = false;
        private void dataGridSettings_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            _cellDirty = true;
        }

        private void dataGridSettings_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (dataGridSettings.Rows[e.RowIndex].IsNewRow)
            {
                bool empty = true;
                foreach (DataGridViewCell cell in dataGridSettings.Rows[e.RowIndex].Cells)
                {
                    if (cell.Value != cell.DefaultNewRowValue)
                    {
                        empty = false;
                        break;
                    }
                }

                //we have nothing in the row
                if (empty)
                {
                    // Clear the row error in case the user presses ESC.   
                    dataGridSettings.Rows[e.RowIndex].ErrorText = String.Empty;
                    dataGridSettings.CancelEdit();
                    dataGridSettings.ClearSelection();
                    _cellDirty = false;
                    return;
                }
            }


            // Validate the Section, Name entry by disallowing empty strings.
            DataGridViewCell section = dataGridSettings.Rows[e.RowIndex].Cells["colSection"];
            DataGridViewCell name = dataGridSettings.Rows[e.RowIndex].Cells["colName"];
            if (String.IsNullOrEmpty(section.FormattedValue.ToString()))
            {
                dataGridSettings.Rows[e.RowIndex].ErrorText =
                    "Section must not be empty";
                e.Cancel = true;
            }
            else if (String.IsNullOrEmpty(name.FormattedValue.ToString()))
            {
                dataGridSettings.Rows[e.RowIndex].ErrorText =
                    "Name must not be empty";
                e.Cancel = true;
            }
            
        }

        private void dataGridSettings_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            _cellDirty = false;
            // Clear the row error in case the user presses ESC.   
            dataGridSettings.Rows[e.RowIndex].ErrorText = String.Empty;
            dataGridSettings.CancelEdit();
            dataGridSettings.ClearSelection();

        }

        //Script Validation
        private void dataGridScripts_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (!_cellDirty)
            {
                // Clear the row error in case the user presses ESC.   
                dataGridScripts.Rows[e.RowIndex].ErrorText = String.Empty;
                return;
            }
            // Validate the Section, Name entry by disallowing empty strings.
            if (dataGridScripts.Columns[e.ColumnIndex].Name == "colScriptName")
            {
                if (String.IsNullOrEmpty(e.FormattedValue.ToString()))
                {
                    dataGridScripts.Rows[e.RowIndex].ErrorText =
                        "Name must not be empty";
                    e.Cancel = true;
                }
            }
            else if (dataGridScripts.Columns[e.ColumnIndex].Name == "colScriptData")
            {
                if (String.IsNullOrEmpty(e.FormattedValue.ToString()))
                {
                    dataGridScripts.Rows[e.RowIndex].ErrorText =
                        "Script must not be empty";
                    e.Cancel = true;
                }
            }
        }

        private void dataGridScripts_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            _cellDirty = true;
        }

        private void dataGridScripts_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (dataGridScripts.Rows[e.RowIndex].IsNewRow)
            {
                bool empty = true;
                foreach (DataGridViewCell cell in dataGridScripts.Rows[e.RowIndex].Cells)
                {
                    if (cell.Value != cell.DefaultNewRowValue)
                    {
                        empty = false;
                        break;
                    }
                }

                //we have nothing in the row
                if (empty)
                {
                    // Clear the row error in case the user presses ESC.   
                    dataGridScripts.Rows[e.RowIndex].ErrorText = String.Empty;
                    dataGridScripts.CancelEdit();
                    dataGridScripts.ClearSelection();
                    _cellDirty = false;
                    return;
                }
            }


            // Validate the Section, Name entry by disallowing empty strings.
            DataGridViewCell name = dataGridScripts.Rows[e.RowIndex].Cells["colScriptName"];
            DataGridViewCell data = dataGridScripts.Rows[e.RowIndex].Cells["colScriptData"];
            DataGridViewCell source = dataGridScripts.Rows[e.RowIndex].Cells["colSource"];
            DataGridViewCell type = dataGridScripts.Rows[e.RowIndex].Cells["colType"];
            if (String.IsNullOrEmpty(data.FormattedValue.ToString()) && String.IsNullOrEmpty(source.FormattedValue.ToString()))
            {
                dataGridScripts.Rows[e.RowIndex].ErrorText =
                    "Script or Source is required";
                e.Cancel = true;
            }
            
            if (String.IsNullOrEmpty(name.FormattedValue.ToString()))
            {
                dataGridScripts.Rows[e.RowIndex].ErrorText =
                    "Name must not be empty";
                e.Cancel = true;
            }

            if (String.IsNullOrEmpty(type.FormattedValue.ToString()))
            {
                dataGridScripts.Rows[e.RowIndex].ErrorText =
                    "Please select a type it can not be empty";
                e.Cancel = true;
            }

        }

        private void dataGridScripts_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            _cellDirty = false;
            // Clear the row error in case the user presses ESC.   
            dataGridScripts.Rows[e.RowIndex].ErrorText = String.Empty;
            dataGridScripts.CancelEdit();
            dataGridScripts.ClearSelection();

        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void confSettings_Enter(object sender, EventArgs e)
        {

        }
    }
}
